# my functions for file creation/deletion operations
# also for file path string stuff
import os, shutil

# function to format a path string correctly:
# - no duplicate slashes
# - no backward slashes
# - nothing ends with a slash
def get_path_str(path):
  
  # check params
  if (type(path) != str):
    return ""
  
  # else work on the string
  rtn_str = ""
  while (path != ""):
    if (path[0] in "/\\"):
      rtn_str += '/'
      while (len(path) > 0 and path[0] in "/\\"):
        path = path[1:]
    if (len(path) > 0):
      rtn_str += path[0]
    path = path[1:]
  
  # check if there is an ending slash
  if (rtn_str[-1] == '/'):
    rtn_str = rtn_str[:-1]
  
  # done!
  return rtn_str
  
# function to check if a file/folder path exists or not
def f_exists(path):
  path = get_path_str(path)
  return os.path.exists(path)
  
# function to check if a file path actually points to a file
def is_file(path):
  path = get_path_str(path)
  return os.path.isfile(path)
  
# function to check if a folder path actually points to a folder
def is_folder(path):
  path = get_path_str(path)
  return os.path.isdir(path)

# function to get the file name portion of a file path
def get_file_name(path):
  
  # check params
  if (type(path) != str):
    return None
  path = get_path_str(path)
  
  # get the full path of the file/folder
  if (f_exists(path)):
    path = os.path.abspath(path)
  
  # start reading path string
  string = ""
  for i in range(len(path) - 1, -1, -1):
    if (path[i] == '/'):
      for j in range(i + 1, len(path)):
        string += path[j]
      break
  
  # done!
  return string

# function to get the base path of a file or folder
def get_base_path(path, is_file):
  
  # check params
  if ((type(path) != str) or (type(is_file) != bool)):
    return None
  path = get_path_str(path)
  
  # get the full path of the file/folder
  if (f_exists(path)):
    path = get_path_str(os.path.abspath(path))
  
  # work on path
  if (is_file): 
    while (path != ""):
      if (path[-1] == '/'):
        path = path[:-1]
        break
      path = path[:-1]
  return path

# function to get the base path of a file or folder
def get_base_folder_name(path, is_file, folder_as_file):
  
  # check params
  if ((type(path) != str) or (type(is_file) != bool) or (type(folder_as_file) != bool)):
    return None
  path = get_path_str(path)

  # reuse get_base_path() and get_file_name()
  if ((is_file) or (is_file == False and folder_as_file)):
    return get_file_name(get_base_path(path, True))
  return get_file_name(get_base_path(path, False))

# function to copy a file to another location
def cp_file(src, dest):
  
  # check params
  if ((f_exists(src) == False) or (is_file(src) == False)):
    return False
  
  # depending on dest 2 things can happen
  # - dest defines a new name for the file to create/replace
  # - dest is just a folder
  if (f_exists(dest) == False): # copy as a new file in that location    
    # get the base path of dest
    base_path = get_base_path(dest, True)
    # create the base path if it does not exist
    if (f_exists(base_path) == False):
      os.makedirs(base_path)
    # copy the file to the directory
    shutil.copy(src, base_path + "/" + get_file_name(dest))
  elif (f_exists(dest) == True and is_file(dest)):
    # get the base path of dest
    base_path = get_base_path(dest, True)
    # remove the file at dest
    os.remove(dest)
    # copy the file in src to dest
    shutil.copy(src, base_path + "/" + get_file_name(dest))
  elif (f_exists(dest) == True and is_folder(dest)):
    # copy the file in src to dest
    shutil.copy(src, dest + "/" + get_file_name(src))
  
  # done!
  return True 

# function to return a folder tree (file/folders)
def list_folder_tree(src):
  
  # check params
  if (type(src) != str or f_exists(src) == False):
    return []
  
  # get the list of all files inside the mod folder first (files/folders)  
  # infinite loop moment
  f_list = [src]
  tmp_list = []
  while (True):
    # reset tmp_list
    tmp_list = []
    # add the new files in f_list folders
    # that are not present in it to tmp_list
    for f in f_list:
      # add new folder/file
      if (f not in tmp_list):
        tmp_list.append(f)
      # if f is a folder check its contents so they can be added to tmp_list
      if (is_folder(f)):
        for int_f in os.listdir(f):
          # add new folder/file
          if ((f + "/" + int_f) not in tmp_list):
            tmp_list.append(f + "/" + int_f)
    # when there is nothing more new added to tmp_list end the infinite loop
    if (f_list == tmp_list):
      break
    # otherwise keep adding the mising files
    f_list = tmp_list
  # ^ I honestly wasn't expecting this loop to work at first lolll
  return f_list
  
# function to copy a folder to another folder (a file like copy)
def cp_folder(src, dest, treat_as_file):
  
  # check params
  if ((f_exists(src) == False) or (is_folder(src) == False)
      or (type(dest) != str) or (type(treat_as_file) != bool)):
    return False
  
  # check the existence of dest
  if (f_exists(dest) == False):
    os.makedirs(dest)
  
  # check if src is to be treated as a file (i.e. copy the folder as well and not just its contents)
  if (treat_as_file):
    dest = dest + "/" + get_base_folder_name(src, False)
    if (f_exists(dest) == False):
      os.makedirs(dest)
  
  # get the list of all files inside the mod folder first (files/folders)  
  # infinite loop moment
  f_list = list_folder_tree(src)
  
  # start copying the files
  for f in f_list:
    dest_f_path = dest + "/" + f.replace(src, "")
    if (is_file(f)):
      cp_file(f, dest_f_path)
    elif (is_folder(f) and (is_folder(dest_f_path) == False)):
      os.makedirs(dest_f_path)
  
  # done!    
  return True

# function to delete a file
def rm_file(path):
  
  # check params
  if (type(path) != str or f_exists(path) == False or is_file(path) == False):
    return False
  
  # remove the file
  os.remove(path)
  return True
  
# function to delete a folder with/without contents, don't care if the folder does not exist
def rm_folder(path):
  
  # check params
  if (type(path) != str or f_exists(path) == False or is_folder(path) == False):
    return False
    
  # remove the folder (get the tree list)
  f_list = list_folder_tree(path)
  for i in range(len(f_list) - 1, -1, -1):
    if (is_file(f_list[i])):
      rm_file(f_list[i])
    elif (is_folder(f_list[i])):
      os.rmdir(f_list[i])
  
  # done!
  return True

# function to get the size of a file
def get_file_size(path):
  
  # check params
  if (is_file(path) == False):
    return 0
  return os.path.getsize(get_path_str(path))
